home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / russell / gc32.lha / debug_malloc.c < prev    next >
C/C++ Source or Header  |  1993-07-16  |  12KB  |  429 lines

  1. # include "gc_private.h"
  2. # define START_FLAG ((word)0xfedcedcb)
  3. # define END_FLAG ((word)0xbcdecdef)
  4.     /* Stored both one past the end of user object, and one before    */
  5.     /* the end of the object as seen by the allocator.        */
  6.  
  7. /* Object header */
  8. typedef struct {
  9.     char * oh_string;    /* object descriptor string    */
  10.     word oh_int;        /* object descriptor integers    */
  11.     word oh_sz;        /* Original malloc arg.        */
  12.     word oh_sf;            /* start flag */
  13. } oh;
  14. /* The size of the above structure is assumed not to dealign things,    */
  15. /* and to be a multiple of the word length.                */
  16.  
  17. #define DEBUG_BYTES (sizeof (oh) + sizeof (word))
  18. #undef ROUNDED_UP_WORDS
  19. #define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
  20.  
  21. /* Check whether object with base pointer p has debugging info    */ 
  22. /* p is assumed to point to a legitimate object in our part    */
  23. /* of the heap.                            */
  24. bool GC_has_debug_info(p)
  25. ptr_t p;
  26. {
  27.     register oh * ohdr = (oh *)p;
  28.     register ptr_t body = (ptr_t)(ohdr + 1);
  29.     register word sz = GC_size((ptr_t) ohdr);
  30.     
  31.     if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
  32.         || sz < sizeof (oh)) {
  33.         return(FALSE);
  34.     }
  35.     if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
  36.     if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
  37.         return(TRUE);
  38.     }
  39.     return(FALSE);
  40. }
  41.  
  42. /* Store debugging info into p.  Return displaced pointer. */
  43. /* Assumes we don't hold allocation lock.           */
  44. ptr_t GC_store_debug_info(p, sz, string, integer)
  45. register ptr_t p;    /* base pointer */
  46. word sz;     /* bytes */
  47. char * string;
  48. word integer;
  49. {
  50.     register word * result = (word *)((oh *)p + 1);
  51.     DCL_LOCK_STATE;
  52.     
  53.     /* There is some argument that we should dissble signals here.    */
  54.     /* But that's expensive.  And this way things should only appear    */
  55.     /* inconsistent while we're in the handler.                */
  56.     LOCK();
  57.     ((oh *)p) -> oh_string = string;
  58.     ((oh *)p) -> oh_int = integer;
  59.     ((oh *)p) -> oh_sz = sz;
  60.     ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
  61.     ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
  62.          result[ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
  63.     UNLOCK();
  64.     return((ptr_t)result);
  65. }
  66.  
  67. /* Check the object with debugging info at p         */
  68. /* return NIL if it's OK.  Else return clobbered    */
  69. /* address.                        */
  70. ptr_t GC_check_annotated_obj(ohdr)
  71. register oh * ohdr;
  72. {
  73.     register ptr_t body = (ptr_t)(ohdr + 1);
  74.     register word gc_sz = GC_size((ptr_t)ohdr);
  75.     if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
  76.         return((ptr_t)(&(ohdr -> oh_sz)));
  77.     }
  78.     if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
  79.         return((ptr_t)(&(ohdr -> oh_sf)));
  80.     }
  81.     if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) {
  82.         return((ptr_t)((word *)ohdr + BYTES_TO_WORDS(gc_sz)-1));
  83.     }
  84.     if (((word *)body)[ROUNDED_UP_WORDS(ohdr -> oh_sz)]
  85.         != (END_FLAG ^ (word)body)) {
  86.         return((ptr_t)((word *)body + ROUNDED_UP_WORDS(ohdr -> oh_sz)));
  87.     }
  88.     return(0);
  89. }
  90.  
  91. void GC_print_obj(p)
  92. ptr_t p;
  93. {
  94.     register oh * ohdr = (oh *)GC_base(p);
  95.     
  96.     GC_err_printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh));
  97.     GC_err_puts(ohdr -> oh_string);
  98.     GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
  99.                           (unsigned long)(ohdr -> oh_sz));
  100. }
  101. void GC_print_smashed_obj(p, clobbered_addr)
  102. ptr_t p, clobbered_addr;
  103. {
  104.     register oh * ohdr = (oh *)GC_base(p);
  105.     
  106.     GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
  107.                                 (unsigned long)p);
  108.     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))) {
  109.         GC_err_printf1("<smashed>, appr. sz = %ld)\n",
  110.                    BYTES_TO_WORDS(GC_size((ptr_t)ohdr)));
  111.     } else {
  112.         GC_err_puts(ohdr -> oh_string);
  113.         GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
  114.                               (unsigned long)(ohdr -> oh_sz));
  115.     }
  116. }
  117.  
  118. void GC_check_heap_proc();
  119.  
  120. void GC_start_debugging()
  121. {
  122.     GC_check_heap = GC_check_heap_proc;
  123.     GC_debugging_started = TRUE;
  124.     GC_register_displacement((word)sizeof(oh));
  125. }
  126.  
  127. # ifdef __STDC__
  128.     extern_ptr_t GC_debug_malloc(size_t lb, char * s, int i)
  129. # else
  130.     extern_ptr_t GC_debug_malloc(lb, s, i)
  131.     size_t lb;
  132.     char * s;
  133.     int i;
  134. # endif
  135. {
  136.     extern_ptr_t result = GC_malloc(lb + DEBUG_BYTES);
  137.     
  138.     if (result == 0) {
  139.         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
  140.                    (unsigned long) lb);
  141.         GC_err_puts(s);
  142.         GC_err_printf1(":%ld)\n", (unsigned long)i);
  143.         return(0);
  144.     }
  145.     if (!GC_debugging_started) {
  146.         GC_start_debugging();
  147.     }
  148.     return (GC_store_debug_info(result, (word)lb, s, (word)i));
  149. }
  150.  
  151. #ifdef STUBBORN_ALLOC
  152. # ifdef __STDC__
  153.     extern_ptr_t GC_debug_malloc_stubborn(size_t lb, char * s, int i)
  154. # else
  155.     extern_ptr_t GC_debug_malloc_stubborn(lb, s, i)
  156.     size_t lb;
  157.     char * s;
  158.     int i;
  159. # endif
  160. {
  161.     extern_ptr_t result = GC_malloc_stubborn(lb + DEBUG_BYTES);
  162.     
  163.     if (result == 0) {
  164.         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
  165.                    (unsigned long) lb);
  166.         GC_err_puts(s);
  167.         GC_err_printf1(":%ld)\n", (unsigned long)i);
  168.         return(0);
  169.     }
  170.     if (!GC_debugging_started) {
  171.         GC_start_debugging();
  172.     }
  173.     return (GC_store_debug_info(result, (word)lb, s, (word)i));
  174. }
  175.  
  176. void GC_debug_change_stubborn(p)
  177. extern_ptr_t p;
  178. {
  179.     register extern_ptr_t q = GC_base(p);
  180.     register hdr * hhdr;
  181.     
  182.     if (q == 0) {
  183.         GC_err_printf1("Bad argument: 0x%lx to GC_debug_change_stubborn\n",
  184.                    (unsigned long) p);
  185.         ABORT("GC_debug_change_stubborn: bad arg");
  186.     }
  187.     hhdr = HDR(q);
  188.     if (hhdr -> hb_obj_kind != STUBBORN) {
  189.         GC_err_printf1("GC_debug_change_stubborn arg not stubborn: 0x%lx\n",
  190.                    (unsigned long) p);
  191.         ABORT("GC_debug_change_stubborn: arg not stubborn");
  192.     }
  193.     GC_change_stubborn(q);
  194. }
  195.  
  196. void GC_debug_end_stubborn_change(p)
  197. extern_ptr_t p;
  198. {
  199.     register extern_ptr_t q = GC_base(p);
  200.     register hdr * hhdr;
  201.     
  202.     if (q == 0) {
  203.         GC_err_printf1("Bad argument: 0x%lx to GC_debug_end_stubborn_change\n",
  204.                    (unsigned long) p);
  205.         ABORT("GC_debug_end_stubborn_change: bad arg");
  206.     }
  207.     hhdr = HDR(q);
  208.     if (hhdr -> hb_obj_kind != STUBBORN) {
  209.         GC_err_printf1("debug_end_stubborn_change arg not stubborn: 0x%lx\n",
  210.                    (unsigned long) p);
  211.         ABORT("GC_debug_end_stubborn_change: arg not stubborn");
  212.     }
  213.     GC_end_stubborn_change(q);
  214. }
  215.  
  216. #endif /* STUBBORN_ALLOC */
  217.  
  218. # ifdef __STDC__
  219.     extern_ptr_t GC_debug_malloc_atomic(size_t lb, char * s, int i)
  220. # else
  221.     extern_ptr_t GC_debug_malloc_atomic(lb, s, i)
  222.     size_t lb;
  223.     char * s;
  224.     int i;
  225. # endif
  226. {
  227.     extern_ptr_t result = GC_malloc_atomic(lb + DEBUG_BYTES);
  228.     
  229.     if (result == 0) {
  230.         GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
  231.                   (unsigned long) lb);
  232.         GC_err_puts(s);
  233.         GC_err_printf1(":%ld)\n", (unsigned long)i);
  234.         return(0);
  235.     }
  236.     if (!GC_debugging_started) {
  237.         GC_start_debugging();
  238.     }
  239.     return (GC_store_debug_info(result, (word)lb, s, (word)i));
  240. }
  241.  
  242. # ifdef __STDC__
  243.     extern_ptr_t GC_debug_malloc_uncollectable(size_t lb, char * s, int i)
  244. # else
  245.     extern_ptr_t GC_debug_malloc_uncollectable(lb, s, i)
  246.     size_t lb;
  247.     char * s;
  248.     int i;
  249. # endif
  250. {
  251.     extern_ptr_t result = GC_malloc_uncollectable(lb + DEBUG_BYTES);
  252.     
  253.     if (result == 0) {
  254.         GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
  255.                   (unsigned long) lb);
  256.         GC_err_puts(s);
  257.         GC_err_printf1(":%ld)\n", (unsigned long)i);
  258.         return(0);
  259.     }
  260.     if (!GC_debugging_started) {
  261.         GC_start_debugging();
  262.     }
  263.     return (GC_store_debug_info(result, (word)lb, s, (word)i));
  264. }
  265.  
  266.  
  267. # ifdef __STDC__
  268.     void GC_debug_free(extern_ptr_t p)
  269. # else
  270.     void GC_debug_free(p)
  271.     extern_ptr_t p;
  272. # endif
  273. {
  274.     register extern_ptr_t base = GC_base(p);
  275.     register ptr_t clobbered;
  276.     
  277.     if (base == 0) {
  278.         GC_err_printf1("Attempt to free invalid pointer %lx\n",
  279.                    (unsigned long)p);
  280.         ABORT("free(invalid pointer)");
  281.     }
  282.     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
  283.         GC_err_printf1(
  284.               "GC_debug_free called on pointer %lx wo debugging info\n",
  285.               (unsigned long)p);
  286.     } else {
  287.       clobbered = GC_check_annotated_obj((oh *)base);
  288.       if (clobbered != 0) {
  289.         GC_err_printf0("GC_debug_free: found smashed object at ");
  290.         GC_print_smashed_obj(p, clobbered);
  291.       }
  292.     }
  293.     GC_free(GC_base(p));
  294. }
  295.  
  296. # ifdef __STDC__
  297.     extern_ptr_t GC_debug_realloc(extern_ptr_t p, size_t lb, char *s, int i)
  298. # else
  299.     extern_ptr_t GC_debug_realloc(p, lb, s, i)
  300.     extern_ptr_t p;
  301.     size_t lb;
  302.     char *s;
  303.     int i;
  304. # endif
  305. {
  306.     register extern_ptr_t base = GC_base(p);
  307.     register ptr_t clobbered;
  308.     register extern_ptr_t result = GC_debug_malloc(lb, s, i);
  309.     register size_t copy_sz = lb;
  310.     register size_t old_sz;
  311.     register hdr * hhdr;
  312.     
  313.     if (p == 0) return(GC_debug_malloc(lb, s, i));
  314.     if (base == 0) {
  315.         GC_err_printf1(
  316.               "Attempt to free invalid pointer %lx\n", (unsigned long)p);
  317.         ABORT("realloc(invalid pointer)");
  318.     }
  319.     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
  320.         GC_err_printf1(
  321.             "GC_debug_realloc called on pointer %lx wo debugging info\n",
  322.             (unsigned long)p);
  323.         return(GC_realloc(p, lb));
  324.     }
  325.     hhdr = HDR(base);
  326.     switch (hhdr -> hb_obj_kind) {
  327. #    ifdef STUBBORN_ALLOC
  328.       case STUBBORN:
  329.         result = GC_debug_malloc_stubborn(lb, s, i);
  330.         break;
  331. #    endif
  332.       case NORMAL:
  333.         result = GC_debug_malloc(lb, s, i);
  334.         break;
  335.       case PTRFREE:
  336.         result = GC_debug_malloc_atomic(lb, s, i);
  337.         break;
  338.       default:
  339.         GC_err_printf0("GC_debug_realloc: encountered bad kind\n");
  340.         ABORT("bad kind");
  341.     }
  342.     clobbered = GC_check_annotated_obj((oh *)base);
  343.     if (clobbered != 0) {
  344.         GC_err_printf0("GC_debug_realloc: found smashed object at ");
  345.         GC_print_smashed_obj(p, clobbered);
  346.     }
  347.     old_sz = ((oh *)base) -> oh_sz;
  348.     if (old_sz < copy_sz) copy_sz = old_sz;
  349.     if (result == 0) return(0);
  350.     bcopy((char *)p, (char *)result, (int) copy_sz);
  351.     return(result);
  352. }
  353.  
  354. /* Check all marked objects in the given block for validity */
  355. /*ARGSUSED*/
  356. void GC_check_heap_block(hbp, dummy)
  357. register struct hblk *hbp;    /* ptr to current heap block        */
  358. word dummy;
  359. {
  360.     register struct hblkhdr * hhdr = HDR(hbp);
  361.     register word sz = hhdr -> hb_sz;
  362.     register int word_no;
  363.     register word *p, *plim;
  364.     
  365.     p = (word *)(hbp->hb_body);
  366.     word_no = HDR_WORDS;
  367.     plim = (word *)((((word)hbp) + HBLKSIZE)
  368.            - WORDS_TO_BYTES(sz));
  369.  
  370.     /* go through all words in block */
  371.     do {
  372.         if( mark_bit_from_hdr(hhdr, word_no)
  373.             && GC_has_debug_info((ptr_t)p)) {
  374.             ptr_t clobbered = GC_check_annotated_obj((oh *)p);
  375.             
  376.             if (clobbered != 0) {
  377.                 GC_err_printf0(
  378.                     "GC_check_heap_block: found smashed object at ");
  379.                 GC_print_smashed_obj((ptr_t)p, clobbered);
  380.             }
  381.         }
  382.         word_no += sz;
  383.         p += sz;
  384.     } while( p <= plim );
  385. }
  386.  
  387.  
  388. /* This assumes that all accessible objects are marked, and that    */
  389. /* I hold the allocation lock.    Normally called by collector.        */
  390. void GC_check_heap_proc()
  391. {
  392.     GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
  393. }
  394.  
  395. struct closure {
  396.     GC_finalization_proc cl_fn;
  397.     extern_ptr_t cl_data;
  398. };
  399.  
  400. # ifdef __STDC__
  401.     void * GC_make_closure(GC_finalization_proc fn, void * data)
  402. # else
  403.     extern_ptr_t GC_make_closure(fn, data)
  404.     GC_finalization_proc fn;
  405.     extern_ptr_t data;
  406. # endif
  407. {
  408.     struct closure * result =
  409.             (struct closure *) GC_malloc(sizeof (struct closure));
  410.     
  411.     result -> cl_fn = fn;
  412.     result -> cl_data = data;
  413.     return((extern_ptr_t)result);
  414. }
  415.  
  416. # ifdef __STDC__
  417.     void GC_debug_invoke_finalizer(void * obj, void * data)
  418. # else
  419.     void GC_debug_invoke_finalizer(obj, data)
  420.     char * obj;
  421.     char * data;
  422. # endif
  423. {
  424.     register struct closure * cl = (struct closure *) data;
  425.     
  426.     (*(cl -> cl_fn))((extern_ptr_t)((char *)obj + sizeof(oh)), cl -> cl_data);
  427.  
  428.